#include <types.h>
#include <stdio.h>
#include <string.h>
#include <console.h>

#include <defs.h>
#include <mmu.h>
#include <param.h>
#include <proc.h>
#include <x86.h>


int kern_init(void) __attribute__((noreturn));
static void mpmain(void);
static void bootothers(void);

int
kern_init(void) {
	extern char edata[], end[];
	memset(edata, 0, end - edata);

	mpinit();

	cons_init();				// init the console

	bootothers();    // start other processors

	// Finish setting up this processor in mpmain.
	mpmain();
}

// Common CPU setup code.
// Bootstrap CPU comes here from mainc().
// Other CPUs jump here from bootother.S.
static void
mpmain(void)
{
  const char *message = "(THU.CST) os is loading ...";
  if(cpunum() != mpbcpu()) {
    ksegment();
    lapicinit(cpunum());
  }
//  vmenable();        // turn on paging
  cprintf("cpu%d: starting\n", cpu->id);
//  idtinit();       // load idt register
  xchg(&cpu->booted, 1);
//  scheduler();     // start running processes
  cprintf("[%d]%s\n", strlen(message), message);
  while (1);
}

static void
bootothers(void)
{
  extern uchar _binary_bootother_start[], _binary_bootother_size[];
  uchar *code;
  struct cpu *c;
  char *stack;

  // Write bootstrap code to unused memory at 0x7000.  The linker has
  // placed the start of bootother.S there.
  code = (uchar *) 0x7000;
  memmove(code, _binary_bootother_start, (uint)_binary_bootother_size);

  for(c = cpus; c < cpus+ncpu; c++){
    if(c == cpus+cpunum())  // We've started already.
      continue;

    // Fill in %esp, %eip and start code on cpu.
//    stack = kalloc();
	stack=(char*)0xfe2000;
    *(void**)(code-4) = stack + KSTACKSIZE;
    *(void**)(code-8) = mpmain;
    lapicstartap(c->id, (uint)code);

    // Wait for cpu to finish mpmain()
    while(c->booted == 0)
      ;
  }
}
